#include "stdafx.h"

HTTPModeEnum gHttpMode;

char	buffin[MAXPACKET];


char	gLine[MAXLINE];
int		gLineNo;
int		charNo;
int		gContentCount;
BOOL	gGettingContent;
int		gContentLength;
BOOL	gIsJSON;
BOOL	gGotContent;
char	gLastChar;
BOOL	gIsNewLine;
BOOL	gAbort;
BOOL gDone;
//extern BOOL	gAbort;
//extern BOOL gDone;

void InitLineTokens()
{
	gLine[0] = '\0';
	gLineNo = 0;
	charNo = 0;
	gLastChar = ' ';
	gIsNewLine = false;
}

void InitParseTokens()
{
	gContentCount = 0;
	gContentLength = 0;
	gGettingContent = false;
	gIsJSON = false;
	gGotContent = false;
	gAbort = false;
}


void ProcessResponse()
{
	//Parse buffin as string
	printf("%s", buffin);
	BOOL skipNext = false;
	for (int i = 0; i < (int)strlen(buffin); i++)
	{
		if (skipNext)
		{
			//Where DOS NL is detected when pointing to \r (of \r\n) by looking at next char 
			//  .. need to skip the next char at the next interation
			skipNext = false;
			continue;
		}
		else if ((i == 0) && (buffin[i] == '\n') && (gLastChar == '\r'))
		{
			//Got DOS newline extended across buffin instances
			gIsNewLine = true;
		}
		else if (MAXLINE>i + 2)
		{
			//When checking for \r\n need to make sure that not at end of buffer
			if ((buffin[i] == '\r') && (buffin[i + 1] == '\n'))
			{
				//Got DOS newline
				skipNext = true;
				gIsNewLine = true;
			}
			else if (buffin[i] == '\n')
			{
				//Got UNIX style NL
				gIsNewLine = true;
			}
		}
		gLastChar = buffin[i];

		//If in HTTP Response Content then send to parser
		if ((gGettingContent) && (!gAbort) && (!gDone))
		{
			if (gIsJSON)
			{
				//If JSON application then send to JSON parser
				if (!ParseJsonString(buffin[i]))
				{
					gAbort = true;
				}
			}
		}


		if (gIsNewLine)
		{
			switch (gLineNo)
			{
			case 0:
				//Expect HTTP/1.1 201 Created
				if (gHttpMode == DOPOST)
				{
					if (strcmp(gLine, "HTTP/1.1 201 Created") != 0)  //POST
					{
						output.PushState();
						output.Enable();
						output.println();
						output.print("POST Failed:");
						output.println(gLine);
						output.PopState();
						gAbort = true;
						return;
					}
					else
						output.println("\r\nPOST done.");
				}
				else if (gHttpMode == DOGET)
				{
					if (strcmp(gLine, "HTTP/1.1 200 OK") != 0)   //GET
					{
						output.PushState();
						output.Enable();
						output.println();
						output.print("GET Failed:");
						output.println(gLine);
						output.PopState();
						gAbort = true;
						return;
					}
					else
						output.println("\r\nGET done.");
				}
				else	if (gHttpMode == DODELETE)
				{
					if (strcmp(gLine, "HTTP/1.1 204 No Content") != 0)
					{
						output.PushState();
						output.Enable();
						output.println();
						output.print("DELETE Failed:");
						output.println(gLine);
						output.PopState();
						gAbort = true;
						return;
					}
					else
					{
						output.println("DELETE completed:");
						gDone = true;
						return;
					}
				}
				else	if (gHttpMode == DOPATCH)
				{
					if (strcmp(gLine, "HTTP/1.1 200 OK") != 0)
					{
						output.PushState();
						output.Enable();
						output.println();
						output.print("PATCH Failed:");
						output.println(gLine);
						output.PopState();
						gAbort = true;
						return;
					}
					else
					{
						output.println("PATCH completed:");
						gDone = true;
						return;
					}
				}
				break;
			case 1:
				//Expect Cache-Control: no-cache
				break;
			case 2:
				//Expect "Content-Length:^<num>"  where ^ is space
				gContentLength = atoi(gLine + strlen("Content-Length:"));
				gContentCount = 0;
				break;
			case 3:
				//Expect "Content-Type:^application/json" where ^ is space
				gIsJSON = false;
				if (strcmp(gLine, "Content-Type: application/json") == 0)
					gIsJSON = true;
				break;
			case 4:
				//Expect Location: https://<AzMSname>.azure-mobile.net/tables/<Table name>/<new record id>
				break;
			case 5:
				//Expect: Server: Microsoft-IIS/8.0
				break;
			case 6:
				//Expect x-zumo-version: Zumo.master.0.1.6.4197.Runtime (Or similar version no.)
				break;
			case 7:
				//Expect: X-Powered-By: ASP.NET
				break;
			case 8:
				//Expect: Set-Cookie: ARRAffinity=.............
				break;
			case 9:
				//Expect: Date:<Current date>
				break;
			}
			if (gLineNo > 8)
			{
				if (strcmp(gLine, "") == 0)
				{
					//There is a blank line before content
					//skipNext2 = true;
					//Header is done so up to content
					gGettingContent = true;
					//If up to get content and there is none we are done.
					if (0 == gContentLength)
						gGotContent = true;
				}
			}
			gLine[0] = '\0';
			charNo = 0;
			gLineNo++;
			skipNext = true;
			gIsNewLine = false;
		}

		else
		{

			gLine[charNo++] = buffin[i];
			gLine[charNo] = '\0';
			if (gGettingContent)
			{
				if (++gContentCount == gContentLength)
					gGotContent = true;
			}
		}
		if (gAbort)
			break;
	}
}

void netError(char* msg)
{
	printf("WSA-ERROR %d - %s\n", WSAGetLastError(), msg);
	netClean();
}

extern "C" BOOL GetResponse(HTTPModeEnum httpMode, bool enableOutput)
{
	output.begin(0);
	if (enableOutput)
		output.Enable();
	else
		output.Disable();

	gHttpMode = httpMode;
	output.println("Wait for answer...\r\n");

	int received;
	InitParseTokens();
	//Note that Response is received in groups the size of defined by MAXPAXCKET
	//If more are available and repeats until done 
	do
	{
		char * ptreceive = buffin;
		ZeroMemory(buffin, MAXPACKET*sizeof(char));
		buffin[0] = '\0';//Overkill
		int totalreceived = 0;
		InitLineTokens();

		//Get next MAXPACKET chars from Response
		do {
			received = netReceive(ptreceive, (MAXPACKET - 1) - totalreceived);
			ptreceive += received;
			totalreceived += received;
			buffin[totalreceived] = '\0';
		} while ((received > 0) && ((MAXPACKET - 1) > totalreceived));

		if (received < 0)
		{
			netError("netReceive");
			gAbort = true;
		}
		else if (!gAbort)     // received bytes
		{
			if (totalreceived>0)
				ProcessResponse(); //Decicphers response including Response type, Content Length and Content. Calls JSON Parser
			if (gAbort)
				output.println("Parsing aborted");
			else if (gDone)
				output.println("Done");
		}

	} while ((received > 0) && (!gGotContent) && (!gAbort));
	output.println("");

	return !gAbort;
}




//////////////////////////////////////////////////////